package com.healthybear.demo.languagechange

import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Configuration
import android.os.Build
import android.provider.Settings
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import java.util.Locale

/**
 * Utility object for managing language switching and preferences in the application.
 * Supports three different implementation methods for language switching.
 */
object LanguageUtils {
    
    private const val PREFS_NAME = "language_preferences"
    private const val KEY_LANGUAGE_CODE = "language_code"
    private const val DEFAULT_LANGUAGE = "en"
    
    /**
     * Enum representing supported languages in the application
     */
    enum class SupportedLanguage(val code: String, val displayName: String) {
        ENGLISH("en", "English"),
        CHINESE("zh", "中文"),
        JAPANESE("ja", "日本語");
        
        companion object {
            fun fromCode(code: String): SupportedLanguage? {
                return values().find { it.code == code }
            }
            
            fun getAllCodes(): List<String> {
                return values().map { it.code }
            }
        }
    }
    
    /**
     * Enum representing different implementation types for language switching
     */
    enum class ImplementationType {
        APP_COMPAT_DELEGATE,    // Method 1: AppCompatDelegate.setApplicationLocales()
        CONFIGURATION_UPDATE,   // Method 2: Configuration.updateConfiguration()
        SYSTEM_SETTINGS        // Method 3: System language settings
    }
    
    /**
     * Save language preference to SharedPreferences
     * Requirement 8.1: Save preference to persistent storage
     */
    fun saveLanguagePreference(context: Context, languageCode: String) {
        try {
            // Validate language code before saving
            val validationResult = ErrorHandler.validateLanguageCode(languageCode)
            if (validationResult is ErrorHandler.ValidationResult.Invalid) {
                ErrorHandler.logErrorWithContext(
                    "LanguageUtils",
                    "Invalid language code, not saving preference",
                    context = mapOf("languageCode" to languageCode, "reason" to validationResult.reason)
                )
                return
            }
            
            val prefs = getSharedPreferences(context)
            val success = prefs.edit()
                .putString(KEY_LANGUAGE_CODE, languageCode)
                .putLong("timestamp", System.currentTimeMillis())
                .commit() // Use commit() to get return value for error checking
            
            if (!success) {
                throw RuntimeException("SharedPreferences commit failed")
            }
            
        } catch (e: Exception) {
            // Handle storage errors gracefully - log but don't crash
            ErrorHandler.handleLanguageSwitchError(
                context,
                e,
                ErrorHandler.ErrorType.STORAGE_ERROR,
                showUserFeedback = false // Don't show UI feedback for background operations
            )
        }
    }
    
    /**
     * Load language preference from SharedPreferences
     * Requirement 8.2: Load and apply saved language preference
     * Requirement 8.4: Fallback to English as default when preference is corrupted
     */
    fun getLanguagePreference(context: Context): String {
        return try {
            val prefs = getSharedPreferences(context)
            val savedLanguage = prefs.getString(KEY_LANGUAGE_CODE, null)
            
            // Validate that the saved language is supported
            if (savedLanguage != null && SupportedLanguage.fromCode(savedLanguage) != null) {
                savedLanguage
            } else {
                // Requirement 8.3: Use device's default language if no preference exists
                val deviceLanguage = Locale.getDefault().language
                if (SupportedLanguage.fromCode(deviceLanguage) != null) {
                    ErrorHandler.logErrorWithContext(
                        "LanguageUtils",
                        "Using device default language",
                        context = mapOf("deviceLanguage" to deviceLanguage)
                    )
                    deviceLanguage
                } else {
                    ErrorHandler.logErrorWithContext(
                        "LanguageUtils",
                        "Device language not supported, using default",
                        context = mapOf("deviceLanguage" to deviceLanguage, "fallback" to DEFAULT_LANGUAGE)
                    )
                    DEFAULT_LANGUAGE
                }
            }
        } catch (e: Exception) {
            // Requirement 8.4: Fallback to English when preference is corrupted
            ErrorHandler.handleStorageError(context, e)
        }
    }
    
    /**
     * Check if the current Android API level is 33 or above
     * Requirement 9.1: Prefer AppCompatDelegate.setApplicationLocales() on Android API 33+
     */
    fun isApiLevel33OrAbove(): Boolean {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
    }
    
    /**
     * Check if the current Android API level supports AppCompatDelegate locale methods
     * Requirement 9.3: Gracefully fallback to alternative methods when API-specific features are unavailable
     */
    fun supportsAppCompatDelegateLocales(): Boolean {
        return isApiLevel33OrAbove()
    }
    
    /**
     * Get the recommended implementation type based on API level
     * Requirement 9.2: Use Configuration.updateConfiguration() approach on older Android versions
     * Requirement 9.4: Use proper version checks and annotations
     */
    fun getRecommendedImplementationType(): ImplementationType {
        return if (isApiLevel33OrAbove()) {
            ImplementationType.APP_COMPAT_DELEGATE
        } else {
            ImplementationType.CONFIGURATION_UPDATE
        }
    }
    
    /**
     * Get current locale from context
     */
    fun getCurrentLocale(context: Context): Locale {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            context.resources.configuration.locales[0]
        } else {
            @Suppress("DEPRECATION")
            context.resources.configuration.locale
        }
    }
    
    /**
     * Validate if a language code is supported
     */
    fun isLanguageSupported(languageCode: String): Boolean {
        return SupportedLanguage.fromCode(languageCode) != null
    }
    
    /**
     * Get SharedPreferences instance for language settings
     */
    private fun getSharedPreferences(context: Context): SharedPreferences {
        return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
    }
    
    /**
     * Method 1: Language switching using AppCompatDelegate.setApplicationLocales()
     * Requirements: 2.1, 2.2, 2.3, 2.4
     * 
     * This method uses the modern Android approach for locale management (API 33+).
     * It applies changes without requiring manual activity restart and automatically
     * handles configuration changes.
     */
    fun setLanguageMethod1(context: Context, languageCode: String): Boolean {
        return try {
            // Validate language code first
            val validationResult = ErrorHandler.validateLanguageCode(languageCode)
            if (validationResult is ErrorHandler.ValidationResult.Invalid) {
                ErrorHandler.handleLanguageSwitchError(
                    context, 
                    IllegalArgumentException(validationResult.reason),
                    ErrorHandler.ErrorType.UNSUPPORTED_LANGUAGE
                )
                return false
            }
            
            // Requirement 2.3: Compatible with Android API level 33 and above
            if (!isApiLevel33OrAbove()) {
                val apiError = IllegalStateException("Method 1 requires API level 33+, current: ${Build.VERSION.SDK_INT}")
                ErrorHandler.handleLanguageSwitchError(
                    context,
                    apiError,
                    ErrorHandler.ErrorType.API_COMPATIBILITY
                )
                return false
            }
            
            // Requirement 2.1: Use AppCompatDelegate.setApplicationLocales() for language switching
            val locale = Locale(languageCode)
            val localeList = LocaleListCompat.forLanguageTags(languageCode)
            
            // Apply the locale using AppCompatDelegate
            AppCompatDelegate.setApplicationLocales(localeList)
            
            // Save the preference for persistence
            saveLanguagePreference(context, languageCode)
            
            ErrorHandler.logErrorWithContext(
                "LanguageUtils", 
                "Language switched successfully using Method 1",
                context = mapOf("languageCode" to languageCode, "method" to "AppCompatDelegate")
            )
            true
            
        } catch (e: Exception) {
            ErrorHandler.handleLanguageSwitchError(
                context,
                e,
                ErrorHandler.ErrorType.API_COMPATIBILITY
            )
            false
        }
    }

    /**
     * Method 2: Language switching using Configuration.updateConfiguration()
     * Requirements: 3.1, 3.2, 3.3, 3.4
     * 
     * This method uses the legacy approach with manual activity restart.
     * It's compatible with older Android API levels and provides direct control
     * over configuration updates.
     */
    fun setLanguageMethod2(context: Context, languageCode: String): Boolean {
        return try {
            // Validate language code first
            val validationResult = ErrorHandler.validateLanguageCode(languageCode)
            if (validationResult is ErrorHandler.ValidationResult.Invalid) {
                ErrorHandler.handleLanguageSwitchError(
                    context, 
                    IllegalArgumentException(validationResult.reason),
                    ErrorHandler.ErrorType.UNSUPPORTED_LANGUAGE
                )
                return false
            }
            
            // Requirement 3.1: Use Configuration.updateConfiguration() for language switching
            val locale = Locale(languageCode)
            Locale.setDefault(locale)
            
            val configuration = Configuration(context.resources.configuration)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                configuration.setLocale(locale)
            } else {
                @Suppress("DEPRECATION")
                configuration.locale = locale
            }
            
            // Update configuration
            @Suppress("DEPRECATION")
            context.resources.updateConfiguration(configuration, context.resources.displayMetrics)
            
            // Save the preference for persistence
            saveLanguagePreference(context, languageCode)
            
            ErrorHandler.logErrorWithContext(
                "LanguageUtils", 
                "Language switched successfully using Method 2",
                context = mapOf("languageCode" to languageCode, "method" to "Configuration")
            )
            true
            
        } catch (e: Exception) {
            ErrorHandler.handleLanguageSwitchError(
                context,
                e,
                ErrorHandler.ErrorType.UNKNOWN_ERROR
            )
            false
        }
    }

    /**
     * Create a context wrapper with the specified locale attached
     * Requirement 3.4: Properly attach the new locale to the base context
     * 
     * This method creates a context wrapper that applies the locale configuration
     * to ensure proper locale handling in activities.
     */
    fun attachBaseContext(context: Context, languageCode: String? = null): Context {
        return try {
            val targetLanguage = languageCode ?: getLanguagePreference(context)
            
            if (!isLanguageSupported(targetLanguage)) {
                android.util.Log.w("LanguageUtils", "Unsupported language code: $targetLanguage, using default")
                return context
            }
            
            val locale = Locale(targetLanguage)
            Locale.setDefault(locale)
            
            val configuration = Configuration(context.resources.configuration)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                configuration.setLocale(locale)
            } else {
                @Suppress("DEPRECATION")
                configuration.locale = locale
            }
            
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                context.createConfigurationContext(configuration)
            } else {
                val contextWrapper = ContextWrapper(context)
                @Suppress("DEPRECATION")
                contextWrapper.resources.updateConfiguration(configuration, contextWrapper.resources.displayMetrics)
                contextWrapper
            }
            
        } catch (e: Exception) {
            android.util.Log.e("LanguageUtils", "Failed to attach base context", e)
            context
        }
    }

    /**
     * Restart the current activity to apply language changes
     * Requirement 3.2: Manually restart the activity to apply changes
     * 
     * This method provides a smooth activity restart mechanism for Method 2
     * language switching that requires manual restart.
     */
    fun restartActivity(activity: Activity) {
        try {
            val intent = activity.intent
            activity.finish()
            activity.startActivity(intent)
            // Add smooth transition animation
            activity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
            
            android.util.Log.i("LanguageUtils", "Activity restarted for language change")
            
        } catch (e: Exception) {
            android.util.Log.e("LanguageUtils", "Failed to restart activity", e)
        }
    }

    /**
     * Method 3: Open system language settings
     * Requirements: 4.1, 4.2, 4.3, 4.4
     * 
     * This method opens the device's system language settings, allowing users
     * to change the device-wide language preference. The app will detect changes
     * when returning from system settings.
     */
    fun openSystemLanguageSettings(context: Context): Boolean {
        return try {
            // Requirement 4.1: Open the device's system language settings
            val intent = Intent().apply {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    // For Android N and above, open the locale settings directly
                    action = Settings.ACTION_LOCALE_SETTINGS
                } else {
                    // For older versions, open general language & input settings
                    action = Settings.ACTION_INPUT_METHOD_SETTINGS
                }
                
                // Add flags to ensure proper intent handling
                flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
            }
            
            // Requirement 4.2: Add proper intent handling and error checking
            if (intent.resolveActivity(context.packageManager) != null) {
                context.startActivity(intent)
                ErrorHandler.logErrorWithContext(
                    "LanguageUtils", 
                    "System language settings opened successfully",
                    context = mapOf("method" to "SystemSettings", "apiLevel" to Build.VERSION.SDK_INT)
                )
                true
            } else {
                // Fallback to general settings if locale settings not available
                val fallbackIntent = Intent(Settings.ACTION_SETTINGS).apply {
                    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
                }
                
                if (fallbackIntent.resolveActivity(context.packageManager) != null) {
                    context.startActivity(fallbackIntent)
                    ErrorHandler.logErrorWithContext(
                        "LanguageUtils", 
                        "Opened general settings as fallback",
                        context = mapOf("reason" to "locale_settings_unavailable")
                    )
                    true
                } else {
                    val error = IllegalStateException("No settings activity available")
                    ErrorHandler.handleLanguageSwitchError(
                        context,
                        error,
                        ErrorHandler.ErrorType.SYSTEM_SETTINGS_ERROR
                    )
                    false
                }
            }
            
        } catch (e: Exception) {
            ErrorHandler.handleLanguageSwitchError(
                context,
                e,
                ErrorHandler.ErrorType.SYSTEM_SETTINGS_ERROR
            )
            false
        }
    }

    /**
     * Check if the system language has changed since last app launch
     * Requirement 4.2: Detect language changes when returning from system settings
     * 
     * This method helps detect if the user changed the system language while
     * in the system settings, allowing the app to update accordingly.
     */
    fun hasSystemLanguageChanged(context: Context): Boolean {
        return try {
            val currentSystemLanguage = getCurrentLocale(context).language
            val savedLanguage = getLanguagePreference(context)
            
            val hasChanged = currentSystemLanguage != savedLanguage
            
            if (hasChanged) {
                android.util.Log.i("LanguageUtils", "System language changed from $savedLanguage to $currentSystemLanguage")
                
                // Update saved preference to match system language if it's supported
                if (isLanguageSupported(currentSystemLanguage)) {
                    saveLanguagePreference(context, currentSystemLanguage)
                }
            }
            
            hasChanged
            
        } catch (e: Exception) {
            android.util.Log.e("LanguageUtils", "Failed to check system language change", e)
            false
        }
    }

    /**
     * Clear all language preferences (useful for testing)
     */
    fun clearLanguagePreferences(context: Context) {
        try {
            getSharedPreferences(context).edit().clear().apply()
        } catch (e: Exception) {
            android.util.Log.e("LanguageUtils", "Failed to clear language preferences", e)
        }
    }
}